#include "viml/compiler.h"
#include "viml/instruction.h"
#include <gtest/gtest.h>

namespace viml {

class CompilerTest : public ::testing::Test {
protected:
    Compiler compiler_;
};

TEST_F(CompilerTest, BasicCompilation) {
    // 测试基本编译功能
    std::string source = "let x = 42";
    auto result = compiler_.compile(source);
    
    EXPECT_TRUE(result.success);
    EXPECT_TRUE(result.errors.empty());
    
    // 验证生成的指令包含加载常量和存储局部变量的指令
    bool has_load_const = false;
    bool has_store_local = false;
    
    for (const auto& instr : result.function->bytecode) {
        if (instr.opcode == OpCode::LOAD_CONST) {
            has_load_const = true;
        }
        if (instr.opcode == OpCode::STORE_LOCAL) {
            has_store_local = true;
        }
    }
    
    EXPECT_TRUE(has_load_const);
    EXPECT_TRUE(has_store_local);
}

TEST_F(CompilerTest, FunctionDefinition) {
    // 测试函数定义编译
    std::string source = "function test() {\n  return 42;\n}";
    auto result = compiler_.compile(source);
    
    EXPECT_TRUE(result.success);
    EXPECT_TRUE(result.errors.empty());
    
    // 验证生成的指令包含函数定义相关的指令
    // 具体的验证取决于编译器实现
}

TEST_F(CompilerTest, ExpressionCompilation) {
    // 测试表达式编译
    std::string source = "let x = 1 + 2 * 3";
    auto result = compiler_.compile(source);
    
    EXPECT_TRUE(result.success);
    EXPECT_TRUE(result.errors.empty());
    
    // 验证生成的指令包含算术运算指令
    bool has_add = false;
    bool has_mul = false;
    
    for (const auto& instr : result.function->bytecode) {
        if (instr.opcode == OpCode::ADD) {
            has_add = true;
        }
        if (instr.opcode == OpCode::MUL) {
            has_mul = true;
        }
    }
    
    EXPECT_TRUE(has_add);
    EXPECT_TRUE(has_mul);
}

TEST_F(CompilerTest, ConditionalCompilation) {
    // 测试条件语句编译
    std::string source = "if (true) {\n  let x = 42;\n}";
    auto result = compiler_.compile(source);
    
    EXPECT_TRUE(result.success);
    EXPECT_TRUE(result.errors.empty());
    
    // 验证生成的指令包含条件跳转指令
    bool has_jump = false;
    
    for (const auto& instr : result.function->bytecode) {
        if (instr.opcode == OpCode::JMP || instr.opcode == OpCode::JMP_IF_FALSE) {
            has_jump = true;
        }
    }
    
    EXPECT_TRUE(has_jump);
}

TEST_F(CompilerTest, EmptySource) {
    std::string source = "";
    auto result = compiler_.compile(source);
    
    // Empty source
    ASSERT_TRUE(result.success);
    ASSERT_TRUE(result.errors.empty());
    ASSERT_EQ(result.function->bytecode.size(), 1);
    ASSERT_EQ(result.function->bytecode[0].opcode, OpCode::RETURN_OP);
}

} // namespace viml